//导入一个node的包  node.js中的一个模块 作用是帮助我们来拼接路径
const path = require('path');

//html-webpack-plugin 是一个 webpack 插件，用于自动创建 HTML 文件并引入打包后的 JavaScript 文件。
const HtmlWebpackPlugin = require('html-webpack-plugin');

//clean-webpack-plugin 是一个 webpack 插件，用于在每次构建之前清理输出目录，以避免旧文件的累积。
const { CleanWebpackPlugin } = require('clean-webpack-plugin');

//mini-css-extract-plugin 是一个 webpack 插件，用于将 CSS 提取到单独的文件中，而不是将其包含在 JavaScript 文件中。
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

//webpack中的所有配置信息都应该写在modules.exports中
module.exports = (env, argv) => {
    //创建一个布尔变量 isProduction，用于判断当前的构建环境是否是生产环境；argv：这是 webpack 配置中的一个参数；argv.mode：这是 argv 对象中的一个属性，它表示当前的构建模式。在 webpack 中，可以通过 --mode 选项来指定构建模式。例如，如果你运行 webpack --mode production，那么 argv.mode 的值就会是 'production
    const isProduction = argv.mode === 'production';
    return {
        //指定入口文件
        entry: './src/index.ts',
        //指定打包文件所在目录
        output: {
            //打包后的名字
            filename: '[name].[contenthash].js',
            //指定打包文件的目录
            path: path.resolve(__dirname, 'dist'),
            publicPath: '/',
        },
        //告诉webpack .ts .js结尾可能是模块，去解析
        resolve: {
            //配置webpack在解析模块时应该尝试的文件扩展名。代码中引用一个模块，但没有指定扩展名时，webpack会尝试添加扩展名来解析文件
            extensions: ['.ts', '.js'],
            //别名（alias）配置对象。别名允许你为一些经常使用的路径设置一个快捷方式，这样在代码中引用这些路径时就不需要写完整的路径了
            alias: {
                //为 @assets 设置了一个别名，指向 src/assets/ 目录
                '@assets': path.resolve(__dirname, 'src/assets/'),
                //为 @components 设置了一个别名，指向 src/components/ 目录
                '@components': path.resolve(__dirname, 'src/components/'),
                // 为 @utils 设置了一个别名，指向 src/utils/ 目录
                '@utils': path.resolve(__dirname, 'src/utils/'),
            },
        },
        //指定webpack打包时要使用的模块
        module: {
            //指定要编译的规则
            rules: [
                {
                    test: /\.html$/,
                    loader: 'html-loader',
                },
                {
                    //test指定的是规则生效的文件  匹配所有以ts结尾的文件
                    test: /\.ts$/,//匹配以ts结尾的所有文件
                    exclude: /node_modules/,//要排除的文件  这个文件不需要编译，因为他是所有的依赖包，所以排除在外
                    use: 'ts-loader',//要使用的loader处理ts结尾的文件
                },
                {
                    //定义了一个正则表达式，用于匹配所有以 .scss 结尾的文件
                    test: /\.scss$/,
                    use: [//要使用的loader处理.scss结尾的文件
                        //根据当前环境（生产环境还是开发环境）选择不同的 loader。如果 isProduction 为 true（即当前是生产环境），则使用 MiniCssExtractPlugin.loader，这个 loader 会将 CSS 提取到单独的文件中。如果 isProduction 为 false（即当前是开发环境），则使用 style-loader，这个 loader 会将 CSS 通过 <style> 标签注入到 HTML 中，方便开发时的热模块替换和调试
                        isProduction ? MiniCssExtractPlugin.loader : 'style-loader',
                        'css-loader',
                        'sass-loader',
                    ],
                },
                {
                    //匹配所有以 .png、.jpg、.jpeg、.gif 或 .svg 结尾的文件。test 属性告诉 webpack 查找所有这些图片文件
                    test: /\.(png|jpg|jpeg|gif|svg)$/,
                    //指定了 webpack 5 中处理静态资源的类型。'asset/resource' 表示这些资源将被作为依赖项处理，并且它们的输出将是一个单独的文件
                    type: 'asset/resource',
                    generator: {//定义了如何生成资源文件的输出路径和文件名
                        filename: 'images/[name].[hash][ext]',//[name]这是资源文件的原始文件名 [hash]：这是资源文件内容的哈希值，用于缓存控制。当文件内容改变时，哈希值也会改变，这样浏览器就会加载新的文件，而不是使用缓存中的旧文件 [ext]：这是资源文件的原始扩展名
                    },
                },
                {
                    //用于定义如何处理字体文件（如 WOFF、WOFF2、EOT、TTF、OTF 等格式）匹配所有以 .woff、.woff2、.eot、.ttf 或 .otf 结尾的文件
                    test: /\.(woff|woff2|eot|ttf|otf)$/,
                    type: 'asset/resource',
                    generator: {
                        filename: 'fonts/[name].[hash][ext]',
                    },
                },
            ]
        },
        //html-webpack-plugin 是一个 webpack 插件，用于自动创建 HTML 文件并引入打包后的 JavaScript 文件。
        plugins: [
            new CleanWebpackPlugin(),//每次打包，先清除上一次打包后生成的文件
            new HtmlWebpackPlugin({//自动生成index.html文件
                title: '这是自定义的一个网页名称',//可以自定义网页名字
                template: './src/index.html',//引用指定的html文件模板，用于打包后生成html文件
                inject: 'body',//指定插件自动生成的 HTML 文件中，应该在哪个位置插入打包后的 JavaScript 和 CSS 文件
            }),
            //通过 MiniCssExtractPlugin 插件将 CSS 从 JS 文件中提取出来，并以指定的命名规则生成独立的 CSS 文件
            new MiniCssExtractPlugin({
                filename: '[name].[contenthash].css',
            }),
        ],
        //配置 webpack 的优化选项
        optimization: {
            //根据当前的构建环境来决定是否启用代码压缩  isProduction 为 true（即当前是生产环境），则 minimize 会被设置为 true，webpack 会使用诸如 TerserPlugin 这样的插件来压缩 JavaScript 代码
            minimize: isProduction,
            //splitChunks 是 webpack 的一个特性，用于代码分割（code splitting），即将代码拆分成多个小块（chunks）
            splitChunks: {
                //chunks: 'all' 这一行代码的作用是指定分割的策略。在这里，'all' 表示所有的 chunks 都会被考虑进行分割，包括同步和异步的 chunks
                chunks: 'all',
            },
        },
        //相当于在项目中安装了一个服务器，它可以让项目展示根据项目改变自动刷新，有点类似于vscode中的起服务 ，webpack-dev-server 是一个小型的 Express 服务器，用于在开发过程中提供静态文件服务和热模块替换（HMR）等功能
        devServer: {
            static: {//指定了 webpack-dev-server 服务的静态文件目录。在这里，它被设置为 dist 目录，意味着当你访问开发服务器时，它会从 dist 目录中提供文件
                directory: path.resolve(__dirname, 'dist'),
            },
            compress: true,//compress：这个选项启用了 gzip 压缩，可以减少传输文件的大小，提高加载速度。
            port: 9000,//port：这个选项指定了 webpack-dev-server 监听的端口号，这里是 9000 端口
            open: true,//open：当设置为 true 时，服务器启动后会自动在默认浏览器中打开应用
            hot: true,//hot：这个选项启用了模块热替换（HMR），允许在开发过程中实时更新模块，而无需刷新整个页面。
            historyApiFallback: true,//historyApiFallback：这个选项用于支持 HTML5 历史模式，当你使用 Vue Router 或 React Router 等前端路由库时，这个选项可以确保路由跳转时页面不会刷新
        },
        devtool: isProduction ? false : 'source-map',//devtool：这个选项根据当前是否是生产环境来设置不同的源映射类型。如果 isProduction 为 true（生产环境），则不生成源映射，因为源映射可能会增加构建文件的大小，并且暴露源代码。如果 isProduction 为 false（开发环境），则生成 source-map 类型的源映射，这样可以在浏览器的开发者工具中将压缩后的代码映射回原始源代码，便于调试
    }
}